package com.hooya.fa.eu.biz.business.service;


import cn.hutool.core.bean.BeanUtil;
import com.hooya.fa.eu.biz.dao.entity.StkOrigDataCollect;
import com.hooya.fa.eu.biz.dao.entity.dto.B2cDataDTO;
import com.hooya.fa.eu.biz.dao.mapper.BuyerMapper;
import com.hooya.fa.eu.biz.dao.mapper.InvoiceMapper;
import com.hooya.fa.eu.biz.dao.mapper.PriceMapper;
import com.hooya.fa.eu.biz.dao.mapper.StkOrigDataCollectMapper;
import com.hooya.fa.eu.biz.dao.mapper.stk.TempXsjlMapper;
import com.hooya.fa.eu.biz.service.impl.CommonService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class Insert_B2C {

    @Autowired
    private StkOrigDataCollectMapper stkOrigdataCollectMapper;

    @Autowired
    private TempXsjlMapper tempXsjlMapper;

    @Autowired
    private PriceMapper priceMapper;

    @Autowired
    private InvoiceMapper invoiceMapper;

    @Autowired
    private BuyerMapper buyerMapper;

    @Autowired
    private CommonService commonService;

    @Transactional
	public void insert_b2c(String start) {
        try {
			log.info("开始执行Insert_B2C");
            // 处理日期
            Map<String, String> dateMap = commonService.dateChange(start);
            String end = dateMap.get("nextMonthStart");


            log.info("开始处理B2C数据，日期范围：{} - {}", start, end);

            // 获取主要数据--根据日期范围查询B2C销售数据
            List<B2cDataDTO> mainData = tempXsjlMapper.getXsjlB2CData(start, end);
            log.info("获取B2C主要数据完成，共获取 {} 条数据", mainData.size());

            // 获取价格数据
            Map<String, Object> priceDataMap = getPrice();
            List<B2cDataDTO> plnPriceData = (List<B2cDataDTO>) priceDataMap.get("plnPriceData");
            List<B2cDataDTO> eurPriceData = (List<B2cDataDTO>) priceDataMap.get("eurPriceData");

            // 添加价格
            List<B2cDataDTO> finalPriceData = addPrice(mainData, plnPriceData, eurPriceData);

            // 添加发票和买家信息  --  这里面有大sql 后续看情况修改
            List<B2cDataDTO> buyerMerge = addInvoiceAndBuyer(finalPriceData);

            commonService.dataVerificationB2c(buyerMerge);

            // 拆分有价格和无价格的数据
            Map<String, List<B2cDataDTO>> splitResult = splitOnPrice(buyerMerge);
            List<B2cDataDTO> finalWithPrice = splitResult.get("withPrice");
            List<B2cDataDTO> finalWithoutPrice = splitResult.get("withoutPrice");

            log.info("B2C数据拆分完成，有价格数据：{} 条，无价格数据：{} 条",
                    finalWithPrice.size(), finalWithoutPrice.size());

            // 转换为实体类并保存
            List<StkOrigDataCollect> withPriceRecords = commonService.convertB2cToStkOrigDataCollect(finalWithPrice, true);
            List<StkOrigDataCollect> withoutPriceRecords = commonService.convertB2cToStkOrigDataCollect(finalWithoutPrice, false);

            commonService.batchInsert(withPriceRecords);
            commonService.batchInsert(withoutPriceRecords);

            log.info("insertB2C 执行完成");
        } catch (Exception e) {
            log.error("处理B2C数据失败", e);
            throw new RuntimeException("处理B2C数据失败", e);
        }
    }

    /**
     * 获取价格数据
     */
    private Map<String, Object> getPrice() {
        log.info("开始获取B2C价格数据");
        Map<String, Object> result = new HashMap<>();

        try {

            List<B2cDataDTO> plnPriceData = priceMapper.getPlnPriceData();
            plnPriceData.forEach(data -> data.setNumber(data.getNumber().split("\\.")[0]));
            List<B2cDataDTO> eurPriceData = priceMapper.getEurPriceData();
            // 使用Stream流实现去重，保留每个orderid和cpbh组合第一次出现的记录
            eurPriceData = new ArrayList<>(eurPriceData.stream()
                    .collect(Collectors.toMap(
                            item -> item.getOrderid() + "|" + item.getCpbh(), // keyMapper
                            item -> item,                                     // valueMapper
                            (existing, replacement) -> existing,              // mergeFunction - 保留第一个
                            LinkedHashMap::new                                // 返回LinkedHashMap保持顺序
                    ))
                    .values());
            result.put("plnPriceData", plnPriceData);
            result.put("eurPriceData", eurPriceData);

            log.info("获取B2C价格数据完成，PLN价格数据 {} 条，EUR价格数据 {} 条",
                    plnPriceData.size(), eurPriceData.size());
        } catch (Exception e) {
            log.error("获取B2C价格数据失败", e);
            throw new RuntimeException("获取B2C价格数据失败", e);
        }

        return result;
    }

    /**
     * 添加价格
     */
    private List<B2cDataDTO> addPrice(List<B2cDataDTO> mainData, List<B2cDataDTO> plnPriceData, List<B2cDataDTO> eurPriceData) {
        log.info("开始添加B2C价格数据");

        // 处理PLN价格  获取键值
        Map<String, List<B2cDataDTO>> plnPriceMap = plnPriceData.stream().collect(Collectors.groupingBy(B2cDataDTO::getNumber));

        //merge -->  mainData数据和plnPriceData数据
        List<B2cDataDTO> plnMerge = new ArrayList<>();
        for (B2cDataDTO mainItem : mainData) {
            String key = mainItem.getSheetnumber();
            if (plnPriceMap.containsKey(key)) {
                List<B2cDataDTO> b2cDataDTOS = plnPriceMap.get(key);
                b2cDataDTOS.forEach(f -> {
                    B2cDataDTO newItem = new B2cDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setPrice(f.getPrice());
                    plnMerge.add(newItem);
                });
            } else {
                plnMerge.add(mainItem);
            }
        }
        // 复制并去除price为空的数据
        List<B2cDataDTO> plnPrice = plnMerge.stream().filter(f -> f.getPrice() != null).collect(Collectors.toList());
        plnPrice.forEach(item -> item.setCurrency("PLN"));
        // 获取price为空的数据
        List<B2cDataDTO> withoutPriceData = plnMerge.stream().filter(f -> f.getPrice() == null).collect(Collectors.toList());

        // 处理EUR价格  获取键值
        Map<String, List<B2cDataDTO>> eurPriceMap = eurPriceData.stream().collect(Collectors.groupingBy(f -> f.getOrderid() + "|" + f.getCpbh()));
        //merge -->  withoutPriceData数据和eurPriceData数据
        List<B2cDataDTO> eurMerge = new ArrayList<>();
        for (B2cDataDTO withoutPriceItem : withoutPriceData) {
            // 创建临时对象 -- 因为后续的withoutPriceData 还要使用 所以不能直接修改
            B2cDataDTO tempItem = new B2cDataDTO();
            BeanUtil.copyProperties(withoutPriceItem, tempItem);
            //获得withoutPriceData 的键
            String key = tempItem.getOrderid() + "|" + tempItem.getCpbh();
            if (eurPriceMap.containsKey(key)) {
                List<B2cDataDTO> b2cDataDTOS = eurPriceMap.get(key);
                b2cDataDTOS.forEach(f -> tempItem.setPrice(f.getPrice()));
                eurMerge.add(tempItem);
            } else {
                eurMerge.add(tempItem);
            }
        }

        List<B2cDataDTO> eurPrice = eurMerge.stream().filter(f -> f.getPrice() != null).collect(Collectors.toList());
        eurPrice.forEach(item -> item.setCurrency("EUR"));

        // 第二遍处理withoutPriceData  查看是否依然存在空值price
        withoutPriceData = eurMerge.stream().filter(f -> f.getPrice() == null).collect(Collectors.toList());
        withoutPriceData.forEach(item -> item.setCurrency(null));
        withoutPriceData.forEach(item -> item.setPrice(null));

        List<B2cDataDTO> finalPriceData = new ArrayList<>();
        finalPriceData.addAll(plnPrice);
        finalPriceData.addAll(eurPrice);
        finalPriceData.addAll(withoutPriceData);

        log.info("添加B2C价格数据完成，共处理 {} 条数据", finalPriceData.size());
        return finalPriceData;
    }

    /**
     * 添加发票和买家信息
     */
    private List<B2cDataDTO> addInvoiceAndBuyer(List<B2cDataDTO> finalPriceData) {
        log.info("开始添加B2C发票和买家信息");

        // 获取发票数据
        List<B2cDataDTO> invoiceB2cData = invoiceMapper.getB2cInvoiceData();

        // 构建发票数据映射
        Map<String, List<B2cDataDTO>> invoiceB2cDataMap = invoiceB2cData.stream()
                .collect(Collectors.groupingBy((dto ->
                        dto.getOrder_id() != null ? dto.getOrder_id() : "null")));

        //merge -->  mainData数据和plnPriceData数据
        List<B2cDataDTO> invoiceMerge = new ArrayList<>();
        for (B2cDataDTO mainItem : finalPriceData) {
            String key = mainItem.getOrderid();
            if (invoiceB2cDataMap.containsKey(key)) {
                List<B2cDataDTO> b2cDataDTOS = invoiceB2cDataMap.get(key);
                b2cDataDTOS.forEach(f -> {
                    B2cDataDTO newItem = new B2cDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setHthm(f.getHthm());
                    invoiceMerge.add(newItem);
                });
            } else {
                invoiceMerge.add(mainItem);
            }
        }

        // 获取买家数据  TODO  --  这里的数据量大 -- 看看是否修改为分页查询 -- 通过循环分页获取数据，最终得到它里面的数据
        List<B2cDataDTO> buyerData = buyerMapper.getB2cBuyer();
        buyerData = new ArrayList<>(buyerData.stream()
                .collect(Collectors.toMap(
                        item -> item.getSheetnumber() + "|" + item.getTocompany(),
                        item -> item,
                        (existing, replacement) -> existing,  // 保留第一个出现的元素
                        LinkedHashMap::new                   // 保持插入顺序
                ))
                .values());

        Map<String, List<B2cDataDTO>> buyerDataMap = buyerData.stream()
                .collect(Collectors.groupingBy(B2cDataDTO::getSheetnumber));

        List<B2cDataDTO> buyerMerge = new ArrayList<>();
        for (B2cDataDTO invoiceItem : invoiceMerge) {
            String key = invoiceItem.getSheetnumber();
            if (buyerDataMap.containsKey(key)) {
                List<B2cDataDTO> b2cDataDTOS = buyerDataMap.get(key);
                b2cDataDTOS.forEach(f -> invoiceItem.setTocompany(f.getTocompany()));
                buyerMerge.add(invoiceItem);
            } else {
                buyerMerge.add(invoiceItem);
            }
        }
        log.info("添加B2C发票和买家信息完成，共处理 {} 条数据", buyerMerge.size());
        return buyerMerge;
    }

    /**
     * 根据sheet_number分页获取买家数据以避免内存溢出，同时保持去重逻辑
     */
    private List<B2cDataDTO> getB2cBuyerBySheetNumberPagination() {
        log.info("开始根据sheet_number分页获取B2C买家数据");

        // 使用LinkedHashMap保持插入顺序，同时去重保留第一个出现的元素
        Map<String, B2cDataDTO> uniqueBuyerDataMap = new LinkedHashMap<>();
        String lastSheetNumber = ""; // 上一批次最后的sheet_number
        int pageSize = 1000000; // 每页大小
        boolean hasMoreData = true;
        int totalFetched = 0;

        while (hasMoreData) {
            try {
                // 根据sheet_number范围获取买家数据
                List<B2cDataDTO> batchBuyerData = buyerMapper.getB2cBuyerBySheetNumberRange(lastSheetNumber, pageSize);

                int fetchedCount = batchBuyerData.size();
                hasMoreData = fetchedCount == pageSize; // 如果获取的数据量等于pageSize，可能还有更多数据
                totalFetched += fetchedCount;

                // 处理当前批次的数据，去重保留第一个出现的元素
                for (B2cDataDTO item : batchBuyerData) {
                    String key = item.getSheetnumber() + "|" + item.getTocompany();
                    // 只有当key不存在时才添加，这样保留的是第一个出现的元素
                    uniqueBuyerDataMap.putIfAbsent(key, item);

                    // 更新最后处理的sheet_number
                    lastSheetNumber = item.getSheetnumber();
                }

                log.debug("已获取B2C买家数据 {} 条唯一数据，当前批次 {} 条，总获取 {} 条",
                        uniqueBuyerDataMap.size(), fetchedCount, totalFetched);

                // 防止无限循环的保护措施
                if (fetchedCount == 0) {
                    break;
                }
            } catch (Exception e) {
                log.error("根据sheet_number分页获取B2C买家数据失败", e);
                throw new RuntimeException("根据sheet_number分页获取B2C买家数据失败", e);
            }
        }

        // 转换为List返回
        List<B2cDataDTO> result = new ArrayList<>(uniqueBuyerDataMap.values());
        log.info("根据sheet_number分页获取B2C买家数据完成，总共获取 {} 条唯一数据", result.size());

        return result;
    }


    /**
     * 拆分有价格和无价格的数据
     */
    private Map<String, List<B2cDataDTO>> splitOnPrice(List<B2cDataDTO> data) {
        Map<String, List<B2cDataDTO>> result = new HashMap<>();

        List<B2cDataDTO> withPrice = data.stream()
                .filter(dto -> dto.getPrice() != null)
                .collect(Collectors.toList());

        List<B2cDataDTO> withoutPrice = data.stream()
                .filter(dto -> dto.getPrice() == null)
                .collect(Collectors.toList());

        result.put("withPrice", withPrice);
        result.put("withoutPrice", withoutPrice);

        return result;
    }



}